import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class Main {

    public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
        System.out.println("created by liangzhaoming for JD Logistics Reverse Treatment R&D Department");
//        try {
        String javaVersion = System.getProperty("java.version");
        if (Float.valueOf(javaVersion.substring(0, javaVersion.length() > 1 ? 2 : 1)) < 1.7) {
            System.out.println("1.7 or more advanced version jdk is required!");
        }
        System.out.println(javaVersion);
        Properties extraProperties = PropertiesLoaderUtils.loadAllProperties("generator.properties");
        String result = checkProperties(extraProperties);
        System.out.println("check properties begin...");
        if (result.equals("success")) {
            System.out.println("check properties success");
            generator(extraProperties);
        } else {
            System.out.println(result);
        }
//        } catch (Exception e) {
//            System.out.println("some exceptions occurred!");
//        }
    }

    private static String checkProperties(Properties extraProperties) {
        String userDir = System.getProperty("user.dir");
        if (!new File(userDir + "/src/main/resources/generator.xml").exists()) {
            return "generator.xml did not exists!";
        }
        if (!new File(userDir + "/src/main/resources/generator.properties").exists()) {
            return "generator.properties did not exists!";
        }
        for (String property : new String[]{
                "pojo.url", "interface.url", "mapper.url", "jdbc.host", "jdbc.username", "jdbc.password", "database.name", "table.name",
                "pojo.name", "pojo.package", "pojo.url", "interface.package", "interface.url", "mapper.package", "mapper.url",}) {
            if (extraProperties.getProperty(property) == null) {
                return property + " did not define!";
            }
        }
        for (String path : new String[]{
                extraProperties.getProperty("pojo.url"),
                extraProperties.getProperty("interface.url"),
                extraProperties.getProperty("mapper.url")}) {
            File file = new File(path);
            if (!file.exists() && file.mkdir() && !file.isDirectory()) {
                return path + " is not a directory";
            }
        }
        return "success";
    }

    private static void generator(Properties extraProperties) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
        System.out.println("generator begin...");
        List<String> warnings = new ArrayList<String>();
        URL url = Main.class.getClassLoader().getResource("generator.xml");
        if (url != null) {
            ConfigurationParser cp = new ConfigurationParser(extraProperties, warnings);
            Configuration config = cp.parseConfiguration(new File(url.getPath()));
            DefaultShellCallback callback = new DefaultShellCallback(true);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);
            if (!CollectionUtils.isEmpty(warnings)) {
                System.out.println("\tprint warnings begin:");
                for (String warn : warnings) {
                    System.out.println("\t" + warn);
                }
                System.out.println("\tprint warnings end");
            }
            System.out.println("generator success");
            transfer(extraProperties);
        } else {
            System.out.println("generator.xml did not exists!");
        }
    }

    private static void transfer(Properties extraProperties) {
        System.out.println("transfer begin...");
        String filePathPrefix = System.getProperty("user.dir") + "/src/main/java/result/";
        String filePath = filePathPrefix + extraProperties.getProperty("pojo.name");
        String separator = System.getProperty("line.separator");
        try {
            copyPojo(filePath, extraProperties);
            rewriteMapperJava(filePath + "Mapper.java", separator, extraProperties);
            rewriteMapperXml(filePath + "Mapper.xml", separator, extraProperties);
            if (!new File(filePathPrefix).delete()) {
                System.out.println("delete result files failed!");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("transfer success");
    }

    private static void copyPojo(String filePath, Properties extraProperties) throws IOException {
        String dir = extraProperties.getProperty("pojo.url");
        dir = dir.endsWith("/") ? dir : dir + "/";
        Files.copy(Paths.get(filePath + ".java"), Paths.get(dir + extraProperties.getProperty("pojo.name") + ".java"));
    }

    private static void rewriteMapperJava(String filePath, String separator, Properties extraProperties) {
        String line;
        String str1 = "result.";
        String str2 = "Selective";
        StringBuilder sb = new StringBuilder();
        String[] methods = new String[]{"insert", "updateByPrimaryKey"};
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            while ((line = br.readLine()) != null) {
                if (line.contains(str1)) {
                    line = line.replaceAll(str1, extraProperties.getProperty("interface.package") + ".");
                } else if (line.contains(methods[0]) || line.contains(methods[1])) {
                    if (line.contains(str2)) {
                        line = line.replaceAll(str2, "");
                    } else {
                        continue;
                    }
                }
                if (StringUtils.isNotBlank(line)) {
                    sb.append(line);
                    sb.append(separator);
                }
            }
        } catch (IOException e) {
            System.out.println("rewrite interface failed!");
            return;
        }
        String dir = extraProperties.getProperty("interface.url");
        dir = dir.endsWith("/") ? dir : dir + "/";
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(dir + extraProperties.getProperty("pojo.name") + "Mapper.java"))) {
            bw.write(sb.toString());
        } catch (IOException e) {
            System.out.println("rewrite interface failed!");
        }
    }

    private static void rewriteMapperXml(String filePath, String separator, Properties extraProperties) {
        String line;
        String str1 = "delete from ";
        String str2 = "result.";
        StringBuilder sb = new StringBuilder();
        String[] tags = new String[]{"</insert>", "</update>"};
        String[] methods = new String[]{"<insert id=\"insert", "<update id=\"updateByPrimaryKey"};
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            boolean delTag = false;
            while ((line = br.readLine()) != null) {
                if (delTag) {
                    if (line.contains(tags[0]) || line.contains(tags[1])) {
                        delTag = false;
                    }
                    continue;
                }
                if (line.contains(str1)) {
                    String prefix = line.substring(0, line.indexOf("delete from "));
                    sb.append(prefix);
                    sb.append("update ");
                    sb.append(extraProperties.getProperty("pojo.name"));
                    sb.append(separator);
                    sb.append(prefix);
                    sb.append("set is_delete = 1");
                    sb.append(separator);
                }
                if (line.contains(str2)) {
                    if (line.contains("Mapper")) {
                        line = line.replaceAll("result\\.", extraProperties.getProperty("interface.package") + ".");
                    } else {
                        line = line.replaceAll("result\\.", extraProperties.getProperty("pojo.package") + ".");
                    }
                }
                if (line.contains(methods[0]) || line.contains(methods[1])) {
                    if (line.contains("Selective")) {
                        line = line.replaceAll("Selective", "");
                        sb.append(line);
                        sb.append(separator);
                    } else {
                        delTag = true;
                    }
                    continue;
                }
                sb.append(line);
                sb.append(separator);
            }
        } catch (IOException e) {
            System.out.println("rewrite mapper failed!");
        }
        String dir = extraProperties.getProperty("mapper.url");
        dir = dir.endsWith("/") ? dir : dir + "/";
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(dir + extraProperties.getProperty("pojo.name") + "Mapper.xml"))) {
            bw.write(sb.toString());
        } catch (IOException e) {
            System.out.println("rewrite mapper failed!");
        }
    }
}
